/******************************************************************************

    action.c

******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "tree.h"
#include "action.h"

#define PRIVATE static
#define PUBLIC

extern double  Last_attribute;

PUBLIC   
double   Answer;

// -----------------------------------------------------------------------
// Semantic stack action code
// -----------------------------------------------------------------------

#define STACKSIZE   511

#undef push 
#undef pop

#define push(n,s) if (s.top > s.start) { *--s.top = n; }\
        else { puts ("calc: stack overflow"); exit(1); }

#define pop(s)   ( s.top < s.end ? *s.top++ : *s.top )

typedef struct _stack
{   
    double   *top,
             *end,
              start [STACKSIZE + 1];
} stack;

stack    Semantic_stack = { Semantic_stack.start + STACKSIZE,
                            Semantic_stack.start + STACKSIZE };

PRIVATE 
void
dump_stack ( stack   s )                        // debugging
{
    double   *top;

    for ( top = s.top;  *top;  ++top ) {
        printf ( "%f ", *top );
    }
    putchar ( '\n' );
}

// -----------------------------------------------------------------------
// abstract syntax tree action code
// -----------------------------------------------------------------------

typedef struct _node { double   item;
                       struct
                      _node    *left,
                               *right;
} node_t;

node_t  *Tree;

typedef struct _stack2
{   
    node_t  **top ,
            **end,
             *start [STACKSIZE + 1];
} stack2;

stack2   Node_stack = { Node_stack.start + STACKSIZE,
                        Node_stack.start + STACKSIZE };

PRIVATE 
node_t *
make_node ( double   item,
            node_t  *left,
            node_t  *right )
{
    register
    node_t    *node;

    node = malloc ( sizeof ( node_t ) );
    if ( node == NULL ) {
        puts ( "malloc failed\n" );
        exit (1);
    }
    node->item = item;
    node->left = left;
    node->right = right;

    return ( node );
}

PRIVATE 
double
post_order_r ( node_t  *tree )
{
    double  left,
            right,
            value;

    if ( tree == NULL ) {
        return  0;
    }
    left = post_order_r ( tree->left );
    right = post_order_r ( tree->right );
    switch ( (int) tree->item ) {
        case '-' :
            if ( right ) {
                value = left - right;
            } else {
                value = -left;
            }
            printf ( " %c ", (char) tree->item );
            break;
        case '+' :
            value = left + right;
            printf ( " %c ", (char) tree->item );
            break;
        case '/' :
            value = left / right;
            printf ( " %c ", (char) tree->item );
            break;
        case '*' :
            value = left * right;
            printf ( " %c ", (char) tree->item );
            break;
        case '^' :
            value = pow ( left, (int) right );
            printf ( " %c ", (char) tree->item );
            break;
        default :
            value = tree->item ;
            printf ( " %.2f ", tree->item );
    }

    return  value;
}

PRIVATE 
double
post_order ( void )
{
    return  post_order_r ( Tree );
}

// -----------------------------------------------------------------------
// grammar action code functions
//
// Duplicate action methods are illustrated. The first part of each action
// function computes the answer directly. The second part builds an
// abstract syntax tree to be processed later in main.
// -----------------------------------------------------------------------

PRIVATE 
void Add ( void )
{
    double   op;
    node_t  *node;

    Answer = pop ( Semantic_stack );                        // direct action
    op = pop ( Semantic_stack );
    if ( op == '+' ) {
        Answer = pop ( Semantic_stack ) + Answer;
    } else {
        Answer = pop ( Semantic_stack ) - Answer;
    }
    push ( Answer, Semantic_stack );

    node = pop ( Node_stack );                          // abstract syntax tree
    Tree = pop ( Node_stack );
    Tree->left = pop ( Node_stack );
    Tree->right = node;
    push ( Tree, Node_stack );
}

PRIVATE 
void Finish ( void )
{
    Answer = pop ( Semantic_stack );

    Tree = pop ( Node_stack );
}

PRIVATE 
void Multiply ( void )
{
    double   op;
    node_t  *node;

    Answer = pop ( Semantic_stack );
    op = pop ( Semantic_stack );
    if ( op == '*' ) {
        Answer = pop ( Semantic_stack ) * Answer;
    } else {
        Answer = pop ( Semantic_stack ) / Answer;
    }
    push ( Answer, Semantic_stack );

    node = pop ( Node_stack );
    Tree = pop ( Node_stack );
    Tree->left = pop ( Node_stack );
    Tree->right = node;
    push ( Tree, Node_stack );
}

PRIVATE 
void Exponent ( void )
{
    Answer = pop ( Semantic_stack );
    Answer = pow ( pop ( Semantic_stack ), (int) Answer );
    push ( Answer, Semantic_stack );

    Tree = make_node ( '^', NULL, NULL );
    Tree->right = pop ( Node_stack );
    Tree->left = pop ( Node_stack );
    push ( Tree, Node_stack );
}

PRIVATE 
void Negate ( void )
{
    Answer = pop ( Semantic_stack );
    push ( -Answer, Semantic_stack );

    Tree = make_node ( '-', NULL, NULL );
    Tree->left = pop ( Node_stack );
    push ( Tree, Node_stack );
}

PRIVATE 
void Push ( void )
{
    push ( Last_attribute, Semantic_stack );

    Tree = make_node ( Last_attribute, NULL, NULL );
    push ( Tree, Node_stack );
}

void DumpStack ( void )
{
    dump_stack ( Semantic_stack );
}

PRIVATE 
void
state ( slk_size_t  number )
{
}

#include "SlkExecute.txt"

PUBLIC   
Action_t
GetAction ( int   display )
{              
    Tree_t      t;
    Action_t    action;

    t = GetTree ( display );
    action.slk.execute = execute;
    action.slk.state = state;
    action.slk.predict = t.predict;
    action.slk.reduce = t.reduce;
    action.show_tree = t.show_tree; 
    action.show_parse_derivation = t.show_parse_derivation;
    action.show_expression = t.show_expression;
    action.post_order = post_order;

    return  action; 
}
